using logging;
using System;

interface ICar{
    void run();
}

class BenzCar: ICar{
    public void run(){ Log.print("奔驰"); }
}

class HummerCar: ICar{
    public void run(){ Log.print("悍马"); }
}

/*-----------------------------------------------------------------*\
    简单工厂
\*-----------------------------------------------------------------*/
class CarSimpleFactory{
    public ICar build_car(string type){
        if(type == "Benz"){
            return new BenzCar();
        }else if(type == "Hummer"){
            return new HummerCar();
        }else  throw new Exception();
    }
}

/* Java Template dynamic creation, like Python::eval()
class SimpleFactory{
    public <T extends Car> T build_car(Class<T> car){
        return (T)Class.forName(car.getName()).newInstance();
    }
} */

/* C# Template dynamic creation, like Python::eval()
public class GenericConcreteCreator<T> : AbstractOrInterfaceOfCreator
where T : AbstractOrInterfaceOfProduct, new(){
    public AbstractOrInterfaceOfProduct CreateProduct(){
        return new T();
    }
} */

/*-----------------------------------------------------------------*\
    工厂方法
\*-----------------------------------------------------------------*/
interface IFactory{
    ICar build_car();
}

class BenzFactory: IFactory{
    // ConcreteProduct 的工作单一化：封装对象的创建流程
    public ICar build_car(){
        return new BenzCar();
    }
}

class HummerFactory: IFactory{
    public ICar build_car(){
        return new HummerCar();
    }
}

/*-----------------------------------------------------------------*\
    解耦的简单工厂
\*-----------------------------------------------------------------*/
class DecoupleFactory{
    // 对单个产品创建流程的封装
    public virtual BenzCar build_benz(){
        return new BenzCar();
    }
    public virtual HummerCar build_hummer(){
        return new HummerCar();
    }

    public ICar build_car(string type){  // 封装了创建已知产品的判断逻辑
        if(type == "Benz")
            return this.build_benz();
        else if(type == "Hummer")
            return this.build_hummer();
        else
            return this.build_car_extend(type);  // 提供新产品的逻辑判断的拓展接口
    }

    public virtual ICar build_car_extend(string type){  // 空实现/默认实现
        throw new Exception();
    }
}

class Demo{
    /*-----------------------------------------------------------------*\
        产品线拓展
    \*-----------------------------------------------------------------*/
    class FutureCar: ICar{
        public void run(){
            Log.print("未来汽车：你想象不到的样子");
        }
    }

    class FutureFactory: IFactory{
        public ICar build_car(){
            return new FutureCar();
        }
    }

    /*-----------------------------------------------------------------*\
        简单工厂的优化
    \*-----------------------------------------------------------------*/
    class NewSimpleFactory{
        private CarSimpleFactory old_factory = new CarSimpleFactory();

        public ICar build_car(string type){  // no need to override
            if(type == "21-century"){
                return new FutureCar();
            }else{
                return old_factory.build_car(type);
            }
        }
    }

    /*-----------------------------------------------------------------*\
        简单工厂的再优化：拓展工厂内部判断逻辑
    \*-----------------------------------------------------------------*/
    class AdvancedSimpleFactory: DecoupleFactory{
        // 封装新产品的创建流程
        public FutureCar build_future_car(){
            return new FutureCar();
        }

        // 重写钩子方法
        public override ICar build_car_extend(string type){
            if(type == "21-century")
                return this.build_future_car();
            else
                return base.build_car_extend(type);
        }
    }

    static void Main(){
        var simple_factory = new CarSimpleFactory();
        var car = simple_factory.build_car("Hummer");
        car.run();

        // 创建哪个对象的逻辑判断，解耦到了客户端实现，因而可以不断的拓展 else if 语句
        var type_runtime = "21-century";
        if (type_runtime == "21-century"){  // 当你拓展ICar子类时，你不需要改写原有代码的逻辑（而简单工厂则不然）
            var factory = new FutureFactory();
            var car2 = factory.build_car();
            car2.run();
        }
        // else if(type_runtime == "Benz"){ } ...

        // Here, we try to update the SimpleFactory
        var simple_factory2 = new NewSimpleFactory();
        var car3 = simple_factory2.build_car(type_runtime);
        car3.run();

        // 对 AdvancedSimpleFactory 的应用
        var decouple_factory = new AdvancedSimpleFactory();
        var car4 = decouple_factory.build_car(type_runtime);
        car4.run();
    }
}